import { Sprite_Base } from '@/sprites/Sprite_Base.js'
import { ImageManager } from '@/managers/ImageManager.js';
import { isBigCharacter } from '@/utils/ImageFileType.js';
import { Sprite } from '@/sprites/Sprite.js';
import { Sprite_Balloon } from '@/sprites/Sprite_Balloon.js';

export class Sprite_Character extends Sprite_Base {
    constructor(character) {
        super();
        this.anchor.x = 0.5;
        this.anchor.y = 1;
        this._character = null;
       
        this._tilesetId = 0;
        this._upperBody = null;
        this._lowerBody = null;
        this._patternWidth=0;
        this._patternHeight=0;

        this.setCharacter(character);
    }

    destroy(opts){
        super.destroy(opts);
        this.deattachHandler();
    }

    bushDepth(){
        return this._character.bushDepth();
    }
    tileId(){
        return this._character.tileId();
    }

    characterIndex(){
        return this._character.characterIndex();
    }

    characterBlockX() {
        return this._isBigCharacter?0:this.characterIndex() % 4 * 3;
    }

    characterBlockY() {
        let index=this.characterIndex();
        return this._isBigCharacter?0:index&(~(index&0x03));
    }

    characterPatternX() {
        return this._character.pattern();
    }

    characterPatternY() {
        return (this._character.direction() - 2) / 2;
    }

    setBlendColor(color){
        super.setBlendColor(color);
        this._upperBody?.setBlendColor(color);
        this._lowerBody?.setBlendColor(color);
    }

    setColorTone(tone){
        super.setColorTone(tone);
        this._upperBody?.setColorTone(tone);
        this._lowerBody?.setColorTone(tone);
    }

    setCharacter(character) {
        if(this._character!=character){
            this.deattachHandler();
            this._character = character;
            this.loadSource();
            if(this._character){
                this.updatePosition();
                this.zIndex=this._character.screenZ();
                this.attachHandler();
            }
        }
    }

    attachHandler(){
        this._character?.on('character:bus',this.onCharacterEvent);
        $gameMap.on('map:tileset',this.onTilesetEvents);
    }

    deattachHandler(){
        this._character?.off('character:bus',this.onCharacterEvent);
        $gameMap.off('tileset:changed',this.onTilesetEvents);
    }

    onCharacterEvent=(type,...args)=>{
        switch(type){
            case 'move':
            case 'jump':
                this.updatePosition();
                break;
            case 'pattern':
            case 'direction':
            case 'characterIndex':
            case 'bushDepth':
                if(!this.isTile()){
                    this.updateCharacterFrame();
                }
                break;
            case 'characterName':
                this.loadCharacterSource();
                break;
            case 'tile':
                this.loadTileSource();
                break;
            case 'animation':
                this.startAnimation(args[0], false, 0);
                break;
            case 'balloon':
                this.startBalloon(args[0]);
                break;
            case 'opacity':
                this.opacity = args[0];break;
            case 'blendMode':
                this.blendMode = args[0];break;
            case 'priority':
                this.zIndex=args[0];
                break;
            case 'transparent':
                this.visible=args[0];
                break;
        }
    }

    onTilesetEvents=(type)=>{
        if(type=='changed'){
            if(this.isTile()){
                this.loadTileSource();
            }
        }
    }

    startBalloon(balloonId) {
        if (!this._balloonSprite) {
            this._balloonSprite = new Sprite_Balloon();
            this._balloonSprite.y=-this.height;
            this.addChild(this._balloonSprite);
        }
        this._balloonSprite.setup(balloonId);
    }

    loadSource() {
        if(this._character){
            if (this.isTile()) {
                this.loadTileSource();
            } else {
                this.loadCharacterSource();
            }
        }else{
            this.visible=false;
        }
    }

    loadTileSource(){
        let tileId=this._character.tileId();
        this._tilesetId = $gameMap.tilesetId();
        let tileset = $gameMap.tileset();
        let setNumber = 5 + tileId>>8;
        ImageManager.loadTileset(tileset.tilesetNames[setNumber]).then(source=>{
            this.source=source;
            this._patternWidth=$gameMap.tileWidth();
            this._patternHeight=$gameMap.tileHeight();
            this.updateTileFrame();
        });
    }

    loadCharacterSource(){
        let characterName=this._character.characterName();
        ImageManager.loadCharacter(characterName).then(source=>{
            this.source=source;
            this.visible=!!source;
            if(source){
                if(isBigCharacter(characterName)){
                    this._patternWidth=source.width / 3;
                    this._patternHeight=source.height/4;
                }else{
                    this._patternWidth=source.width / 12;
                    this._patternHeight=source.height/8;
                }
                this.updateCharacterFrame();
            }
        });
    }

    updateFrame() {
        if (this.isTile()) {
            this.updateTileFrame();
        } else {
            this.updateCharacterFrame();
        }
    }

    updateTileFrame() {
        let tileId=this.tileId();
        let pw = this._patternWidth;
        let ph = this._patternHeight;
        let sx = (((tileId&0x80)>>4)|(tileId&0x07)) * pw;
        let sy = ((tileId&0x38)>>3) * ph;
        this.setFrame(sx, sy, pw, ph);
    }

    updateCharacterFrame() {
        if (this.isInBush()) {
            this.updateHalfBodyFrame();
        } else {
            this.updateWholeFrame();
        }
    }

    updateHalfBodyFrame(){
        let pw = this._patternWidth;
        let ph = this._patternHeight;
        let sx = (this.characterBlockX() + this.characterPatternX()) * pw;
        let sy = (this.characterBlockY() + this.characterPatternY()) * ph;
        this.launchHalfBodySprites();
        let d = this.bushDepth();
        this._upperBody.setFrame(sx, sy, pw, ph - d);
        this._lowerBody.setFrame(sx, sy + ph - d, pw, d);
        this.setFrame(0, 0, 0, 0);
        this._upperBody.y=d;
    }

    launchHalfBodySprites() {
        if (!this._upperBody) {
            ++this.source.refCount;
            this._upperBody = new Sprite(this.source);
            this._upperBody.anchor.x = 0.5;
            this._upperBody.anchor.y = 1;
            this.addChild(this._upperBody);
        }else if(this._upperBody.source!=this.source){
            ++this.source.refCount;
            this._upperBody.source=this.source;
        }
        this._upperBody.visible = true;
        if (!this._lowerBody) {
            ++this.source.refCount;
            this._lowerBody = new Sprite(this.source);
            this._lowerBody.anchor.x = 0.5;
            this._lowerBody.anchor.y = 1;
            this._lowerBody.opacity = 128;
            this.addChild(this._lowerBody);
        }else if(this._lowerBody.source!=this.source){
            ++this.source.refCount;
            this._lowerBody.source=this.source;
        }
        this._lowerBody.visible = true;
    }

    updateWholeFrame(){
        let pw = this._patternWidth;
        let ph = this._patternHeight;
        let sx = (this.characterBlockX() + this.characterPatternX()) * pw;
        let sy = (this.characterBlockY() + this.characterPatternY()) * ph;
        
        if(this._upperBody){
            this._upperBody.visible = false;
            this._lowerBody.visible = false;
        }
        this.setFrame(sx, sy, pw, ph);
    }

    updatePosition(){
        this.x = this._character.screenX();
        this.y = this._character.screenY();
    }

    isBalloonPlaying() {
        return this._balloonSprite?.isPlaying();
    }

    isTile() {
        return this.tileId() > 0;
    }

    isImageChanged() {
        return this._tilesetId != $gameMap.tilesetId() 
    }

    isInBush(){
        return this.bushDepth()>0;
    }
}